using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;

using Peradigm.Framework.Persistence;
using Peradigm.Framework.Persistence.Exceptions;

using Liberty.Domain.Kernel;

namespace Liberty.Persistence.Kernel
{
    [Serializable]
    public class AddressBroker : AbstractBroker
    {
        #region Constants

        private const string SP_ADDRESSWITH = "[Kernel].[AddressWith]";
        private const string SP_SAVE_ADDRESS = "[Kernel].[SaveAddress]";

        private const string FIELD_PREFIX = "@";
        private const string FIELD_OID = "OID";

        private const string FIELD_ADDRESS_OID = "AddressOID";
        private const string FIELD_ROWVERSION = "Version";
        private const string FIELD_ADDRESS1 = "Address1";
        private const string FIELD_ADDRESS2 = "Address2";
        private const string FIELD_CITY = "City";
        private const string FIELD_STATE = "State";
        private const string FIELD_POSTAL_CODE = "PostalCode";
        private const string FIELD_COUNTRY = "Country";

        #endregion

        #region Event Handlers
        #endregion

        #region Methods
        public Address AddressWith( long addressOID )
        {
            SqlCommand cmd = null;
            SafeReader reader = null;
            Address address = null;

            try
            {
                cmd = this.CommandFor( SP_ADDRESSWITH );
                SqlParameter param = new SqlParameter( FIELD_PREFIX + FIELD_ADDRESS_OID, addressOID );
                cmd.Parameters.Add( param );

                reader = this.ExecuteReader( cmd );
                if( reader.Read() )
                {
                    address = this.AddressFrom( reader );
                }
            }
            catch( Exception e )
            {
                #warning  Log the exception here.  This doesn't really work but we can see the exception in the watch window.
                System.Console.WriteLine( e );
                throw;
            }
            finally
            {
                this.Close( cmd );
                this.Close( reader );
            }

            return address;
        }

        public Address Save( Address address )
        {
            SqlCommand cmd = null;
            SafeReader reader = null;

            try
            {
                cmd = this.CommandFor( SP_SAVE_ADDRESS );

                cmd.Parameters.Add( new SqlParameter( FIELD_PREFIX + FIELD_OID, address.Oid ) );
                cmd.Parameters.Add( new SqlParameter( FIELD_PREFIX + FIELD_ROWVERSION, address.Version ) );

                cmd.Parameters.Add( new SqlParameter( FIELD_PREFIX + FIELD_ADDRESS1, address.DeliveryAddress ) );
                cmd.Parameters.Add( new SqlParameter( FIELD_PREFIX + FIELD_ADDRESS2, address.SecondaryUnit ) );
                cmd.Parameters.Add( new SqlParameter( FIELD_PREFIX + FIELD_CITY, address.City ) );
                cmd.Parameters.Add( new SqlParameter( FIELD_PREFIX + FIELD_STATE, address.Province ) );
                cmd.Parameters.Add( new SqlParameter( FIELD_PREFIX + FIELD_POSTAL_CODE, address.PostalCode ) );
                cmd.Parameters.Add( new SqlParameter( FIELD_PREFIX + FIELD_COUNTRY, address.Country ) );

                // Execute and read oid/timestamp
                reader = this.ExecuteReader( cmd );
                if( reader.Read() )
                {
                    address.Oid = reader.GetInt64( FIELD_OID );
                    address.Version = reader.GetRowVersion( FIELD_ROWVERSION );
                }
                else
                {
                    throw new ObjectNotSavedException( "Unable to save address" );
                }
            }
            finally
            {
                this.Close( reader );
                this.Close( cmd );
            }

            return address;
        }
        #endregion

        #region Properties
        #endregion

        #region Private Methods

        internal Address AddressFrom( SafeReader reader )
        {
            Address address;

            address = new Address();

            // Populate properties.
            address.Oid = reader.GetInt64( FIELD_OID );
            address.Version = reader.GetRowVersion( FIELD_ROWVERSION );
            address.DeliveryAddress = reader.GetString( FIELD_ADDRESS1 );
            address.SecondaryUnit = reader.GetString( FIELD_ADDRESS2 );
            address.City = reader.GetString( FIELD_CITY );
            address.Province = reader.GetString( FIELD_STATE );
            address.PostalCode = reader.GetString( FIELD_POSTAL_CODE );
            address.Country = reader.GetString( FIELD_COUNTRY );

            return address;
        }

        private List<Address> AddressesFrom( SqlCommand cmd )
        {
            SafeReader reader;
            List<Address> addresses;

            reader = null;
            try
            {
                reader = this.ExecuteReader( cmd );
                addresses = new List<Address>();
                while( reader.Read() )
                {
                    addresses.Add( this.AddressFrom( reader ) );
                }
            }
            finally
            {
                if( reader != null )
                {
                    this.Close( reader );
                    reader = null;
                }
            }

            return addresses;
        }

        #endregion

        #region Private Properties
        #endregion

        #region Construction and Finalization

        public AddressBroker( SqlTransaction txn )
            : base( txn )
        {
        }

        public AddressBroker( string cxnString )
            : base( cxnString )
        {
        }

        #endregion

        #region Data Elements
        #endregion
    }
}
